package com.area.service.impl;

import com.area.entity.SysArea;
import com.area.mapper.SysAreaMapper;
import com.area.service.SysAreaService;
import com.area.util.HanyuPinyinUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.xiaoymin.knife4j.core.util.CollectionUtils;
import com.github.xiaoymin.knife4j.core.util.StrUtil;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * sys_area 采用国家统一编码 五级 业务实现类
 *
 * @author WangPeiXi
 * @version V1.0.0
 * @date 2022-05-23
 */
@Service
public class SysAreaServiceImpl extends ServiceImpl<SysAreaMapper, SysArea> implements SysAreaService {


    /**
     * 增 insert into 表
     * 删 delete from 表
     * 改 update 表
     *
     * @param sql 查询sql
     * @return boolean
     * @author WangPeiXi
     * @date 2022-05-23
     * @version V1.0.0
     */
    @Override
    public boolean dmlSql(String sql) {
        return baseMapper.dmlSql(sql) > 0 ? true : false;
    }

    /**
     * 生成行政编码
     *
     * @param url
     * @param level
     */
    @Override
    public void generateArea(String url, int level, String provinceCode) {
        List<SysArea> provinces = this.getProvinces(url, provinceCode);
        for (SysArea province : provinces) {
            if (level > 1) {
                System.out.println("++++++++++++++++++++++++++开始获取省 " + province.getName() + "下属市区行政区划信息++++++++++++++++++++++++");
                String cityUrl = url.replace("/index.html", "/" + province.getId().substring(0, 2) + ".html");
                this.getCityAreaCode(cityUrl, province.getId(), level);
            }
        }
        System.out.println(level + "级行政编码结束");
    }

    /**
     * 建立连接 使用Jsoup解析网站
     */
    public Document connect(String url) {
        if (url == null || url.isEmpty()) {
            throw new IllegalArgumentException("无效的url");
        }
        try {
            return Jsoup.connect(url).timeout(new Random().nextInt(9) * 10000).get();
        } catch (IOException e) {
            System.err.println(url + "地址不存在");
            return null;
        }
    }

    /**
     * 获取所有的省份
     *
     * @param url 请求地址：http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2021/index.html
     * @return
     */
    public List<SysArea> getProvinces(String url, String provinceCode) {
        List<SysArea> sysAreas = new ArrayList<>();
        Document connect = this.connect(url);
        Elements rowProvince = connect.select("tr.provincetr");
        for (Element provinceElement : rowProvince) {
            Elements select = provinceElement.select("a");
            for (Element province : select) {
                String code = province.select("a").attr("href");
                String name = province.text();
                SysArea sysArea = new SysArea();
                sysArea.setId(code.replace(".html", "0000000000").trim());
                sysArea.setName(name.trim());
                sysArea.setLevel(1);
                sysArea.setPid("0");
                sysArea.setPinyin(HanyuPinyinUtil.getFirstLetter(sysArea.getName()));
                //保存省级数据
                sysAreas.add(sysArea);
                //单查一个的时候
                if (StrUtil.isNotBlank(provinceCode) && sysArea.getId().equals(provinceCode)) {
                    List<SysArea> arr = new ArrayList<>();
                    arr.add(sysArea);
                    this.save(sysArea);
                    return arr;
                }
            }
        }
        System.out.println("########批量插入省 数量" + sysAreas.size() + "########");
        //保存省
        if (!CollectionUtils.isEmpty(sysAreas)) {
            this.saveBatch(sysAreas);
        }
        return sysAreas;
    }

    /**
     * 获取市行政区划信息
     *
     * @param provinceUrl 省份对应的地址
     * @param parentCode  需要爬取的省份行政区划（对于市的父级代码即为省行政区划）
     * @return
     */
    public void getCityAreaCode(String provinceUrl, String parentCode, int level) {
        try {
            Document connect = connect(provinceUrl);
            Elements rowCity = connect.select("tr.citytr");
            List<SysArea> sysAreas = new ArrayList<>();
            for (Element cityElement : rowCity) {
                String name = cityElement.select("td").text();
                String[] split = name.split(" ");
                SysArea sysArea = new SysArea();
                sysArea.setName(split[1].trim());
                sysArea.setPid(parentCode);
                sysArea.setLevel(2);
                sysArea.setId(split[0].trim());
                sysArea.setPinyin(HanyuPinyinUtil.getFirstLetter(sysArea.getName()));
                sysAreas.add(sysArea);

                String cityUrl = provinceUrl.replace(".html", "/" + split[0].substring(0, 4) + ".html");
                System.out.println("-------------------开始获取市 " + split[1] + "   下属区县行政区划信息-----------------------");
                if (level > 2) {
                    getDownAreaCode(cityUrl, sysArea.getId(), level);
                }
            }
            System.out.println("########批量插入" + parentCode + "市 数量" + sysAreas.size() + "########");
            if (!CollectionUtils.isEmpty(sysAreas)) {
                //保存市级
                this.saveBatch(sysAreas);
            }
        } catch (Exception e) {
            System.err.println(provinceUrl + "市地址不存在");
        }
    }

    /**
     * 获取区县行政区划信息
     *
     * @param cityUrl    城市对应的地址
     * @param parentCode 需要爬取的市行政区划（对于区县的父级代码即为市行政区划）
     * @return
     */
    public void getDownAreaCode(String cityUrl, String parentCode, int level) {
        try {
            List<SysArea> sysAreas = new ArrayList<>();
            Document connect = connect(cityUrl);
            Elements rowDown = connect.select("tr.countytr");
            for (Element downElement : rowDown) {
                String code = downElement.select("a").attr("href");
                String name = downElement.select("td").text();
                String[] split = name.split(" ");
                if (!"市辖区".equals(split[1])) {
                    SysArea sysArea = new SysArea();
                    sysArea.setName(split[1].trim());
                    sysArea.setPid(parentCode);
                    sysArea.setLevel(3);
                    sysArea.setId(split[0].trim());
                    sysArea.setPinyin(HanyuPinyinUtil.getFirstLetter(sysArea.getName()));
                    sysAreas.add(sysArea);
                    String downUrl = cityUrl.replace(parentCode.substring(0, 4) + ".html", code);
                    System.out.println("====================开始获取区县 " + split[1] + " 下属区划信息");

                    if (level > 3) {
                        this.getCountryAreaCodeList(downUrl, sysArea.getId(), level);
                    }

                }
            }

            System.out.println("########批量插入" + parentCode + "区县 数量" + sysAreas.size() + "########");
            if (!CollectionUtils.isEmpty(sysAreas)) {
                //保存区县
                this.saveBatch(sysAreas);
            }
        } catch (Exception e) {
            System.err.println(cityUrl + "区县地址不存在");
        }
    }

    public void getCountryAreaCodeList(String downUrl, String parentCode, int level) {
        try {
            Document connect = connect(downUrl);
            Elements rowDown = connect.select("tr.towntr");
            List<SysArea> sysAreas = new ArrayList<>();
            for (Element downElement : rowDown) {
                String code = downElement.select("a").attr("href");
                String name = downElement.select("td").text();
                String[] split = name.split(" ");
                SysArea sysArea = new SysArea();
                sysArea.setName(split[1]);
                sysArea.setPid(parentCode);
                sysArea.setLevel(4);
                sysArea.setId(split[0]);
                sysArea.setPinyin(HanyuPinyinUtil.getFirstLetter(sysArea.getName()));
                sysAreas.add(sysArea);

                String countryUrl = downUrl.replace(parentCode.substring(0, 6) + ".html", code);
                System.out.println("====================开始获取街道/乡镇 " + split[1] + "下属区划信息");

                if (level > 4) {
                    getVillageAreaCodeList(countryUrl, sysArea.getId());
                }
            }
            System.out.println("########批量插入" + parentCode + "街道/乡镇 数量" + sysAreas.size() + "########");
            if (CollectionUtils.isNotEmpty(sysAreas)) {
                //保存街道数据
                this.saveBatch(sysAreas);
            }
        } catch (Exception e) {
            System.err.println(downUrl + "乡镇地址不存在");
        }
    }


    /**
     * 获取村行政区划信息
     *
     * @param countryUrl
     * @param parentCode
     * @return
     */
    public void getVillageAreaCodeList(String countryUrl, String parentCode) {
        try {
            List<SysArea> villageAreaCodeList = new ArrayList<>();
            Document connect = connect(countryUrl);
            Elements rowDown = connect.select("tr.villagetr");
            for (Element downElement : rowDown) {
                String name = downElement.select("td").text();
                String[] split = name.split(" ");
                SysArea sysArea = new SysArea();
                sysArea.setName(split[2]);
                sysArea.setPid(parentCode);
                sysArea.setLevel(5);
                sysArea.setId(split[0]);
                sysArea.setPinyin(HanyuPinyinUtil.getFirstLetter(sysArea.getName()));
                villageAreaCodeList.add(sysArea);
            }
            System.out.println("########批量插入" + parentCode + "村委会 数量" + villageAreaCodeList.size() + "########");
            if (CollectionUtils.isNotEmpty(villageAreaCodeList)) {
                //批量保存村级数据
                this.saveBatch(villageAreaCodeList);
            }
        } catch (Exception e) {
            System.err.println(countryUrl + "村地址不存在");
        }
        System.out.println("================" + parentCode + " end================");
    }

}
